Not A Java Web Frameworks Survey: Just use Wicket!

‘Java Web Frameworks Survey’ was my first blog posted which was reposted at dzone. Sadly there never was a follow up of it. Although I planned one with:

jZeno, SpringMVC, Seam, Vaadin (at that time: IT-Mill Toolkit), MyFaces, Stripes, Struts, ItsNat, IWebMvc

Now, today just a short, subjective mini-follow-up, maybe someone is interested after all those months … over the months I have additionally investigated JSF, Rails, Vaadin and one more:

  • No comments to JSF :-/
  • Rails is great! Especially the db migrations and other goodies. Partials are a crap: I prefer component based UI frameworks. If you don’t like ruby take a look at grails with autobase.
  • Additionally I highly recommend everyone to take a look at vaadin (‘server-side GWT’) if you need a stateful webapplication. Loading time was a problem for me. Other client-side performance problems can be solved if you use CssLayout, I think.

But for jetwick.com I chose wicket! There were/are 10 reasons:

The most important thing is: if you use ‘mvn jetty:run’ and NetBeans in combination then the development cycle feels like Rails: modify html, css or even Java code. Save and hit F5 in the browser. Nothing more.

The only problem is the database migration (wicket solves only the UI problems). For that I would use liquibase. Or simply run db4o, a nosql solution ‘or’ solr.

Weird Rails Gem

After updating rails I got an error ala `require_frameworks’:RuntimeError: RubyGem version error: rack(1.0.0 not ~> 1.0.1)

The solution is simple:

$ sudo gem install rack –version 1.0.1

2. problem: libxml2 is missing.  try ‘port install libxml2’ or ‘yum install libxml2-devel’

Solution

$ sudo apt-get install libxml2-dev

I also needed libxslt-dev to install the ruhl gem after that nokogiri-1.4.1 and ruhl-1.3.4 were successfully installed.

The only problem is now that ruhl woudn’t work with jruby 😦 …

Simple Database Migration in Java

As I started with Rails development I discovered the very neat feature of database migrations. For me this was the main advantage of using Rails compared to a pure Java solution.

In our Rails application this works without any problems: you can change the database schema as well as migrating the data itself via ruby.

I needed a similar feature at that time in Java and discovered Liquibase, which was relative easy to use and stable. But it has (in my opinion) one major drawback that you have to use xml and for your data migration you even have to use pure SQL. Then you’ll run fast into some issues (e.g. this). But okay, there is also one advantage over the Rails-mechanism: you don’t need to specify the rollback statement (if it is not pure SQL) – liquibase knows from the migration command which revert command it should use.

If you use Hibernate one could stick with SchemaUpdate, but several things don’t work properly with that approach.

Another idea would be to export objects from version 1 and import them into version 2 directly within your application logic e.g. with Groovy … or should I give DMT I try?

Now I thought that Grails could solve this issue better for Java, but to my knowledge (‘Automatic Database Migration’) there is not such a mature migration concept within Grails like in Rails. The Liquibase plugin (grails install-plugin liquibase) or the outdated (?) dbmigrate plugin (grails install-plugin dbmigrate) can solve this as well as autobase, which is based on liquibase too. Does somebody has experiences with that? Here is a mini comparison.

Today I discovered migrate4j, which seems to be the best tool I found so far for pure Java. Another option would be to use JRuby with Rails or simply rails, but this would be a bit of an architecture overkill for the most people, I fear.

Other choices might be:

Do you know other (better?) solutions? How do you do db migrations?

10 steps to the Romaframework – Yet another Java Webframework?

Now the Romaframework in my little series of Meta-Frameworks!

It is a clean Java Web Framework which can use Echo2, but has modules to support other view technologies (I didn’t try). With Echo2 it is not a standard form based web application – it is an Ajax-Rich-Client application. The core is Apache 2.0 licensed.

What to say. Hmmh I will show you my impressions:

user-table

read-user

It was easy and fast to get started and to get it working. So try it out for yourself. For the lazy people I prepared 10 steps to the running application:

  1. Download the Web Wizard distribution
  2. On Windows go to system properties (right click on computer) -> extended -> edit environment variables -> add the ROMA_HOME and specify the download location.
  3. Or if you are riding linux it is faster:
    > export ROMA_HOME=`pwd`
  4. Add ROMA_HOME to the PATH variable.
  5. Then update roma
    > roma check
  6. Create the project skeleton with absolute path name (relative path names lead to an exception [1])
    > roma create webready mytestapp de.uni_bayreuth c:\romatest
  7. The reporting module is missing in the BackOfficeMenu source file. So, either remove the method or install reporting via (before importing into NetBeans):
    > roma install new reporting-jr
    Now add this to the project (WARNING: no automatic undo possible)
    > roma add reporting-jr
  8. I could import this eclipse project into NetBeans (be sure your standard JDK is 1.5 or higher)
    I have to ignore one Warning : “There are inter-project dependencies which could not be resolved. Importing the whole workspace could prevent this problem. (‘org.eclipse.jst.j2ee.internal.web.container’)”
  9. Now press F6 or run this project und you are done! Nothing more is necessary! Wow! Faster than with Ruby on Rails. (I know that all the new technologies are better if you only touch them on the surface, but we will see …)
  10. login = admin and password = admin

[1]
load-project-info:
[echo] Loading project info from ..\romatest/mytestapp/roma-project.xml
ava.io.FileNotFoundException: C:\Users\btn417\Downloads\roma-framework-webwizar
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at java.io.FileInputStream.<init>(FileInputStream.java:66)
at com.oopsconsultancy.xmltask.ant.XmlTask.documentFromFile(XmlTask.java
at com.oopsconsultancy.xmltask.ant.XmlTask.access$000(XmlTask.java:27)
at com.oopsconsultancy.xmltask.ant.XmlTask$InputFile.getDocument(XmlTask
at com.oopsconsultancy.xmltask.ant.XmlTask.execute(XmlTask.java:651)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.jav
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:357)
at org.apache.tools.ant.Target.performTasks(Target.java:385)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
at org.romaframework.wizard.command.project.impl.ProjectAddModuleWizard.
at org.romaframework.wizard.command.project.impl.ProjectAddModuleWizard.
at org.romaframework.wizard.command.project.impl.ProjectCreateWizard.add
at org.romaframework.wizard.command.project.impl.ProjectCreateWizard.exe
at org.romaframework.wizard.MainWizard.main(Unknown Source)
xception in thread “main” C:\Users\btn417\Downloads\roma-framework-webwizard-1.
den angegebenen Pfad nicht finden)
at com.oopsconsultancy.xmltask.ant.XmlTask.execute(XmlTask.java:659)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.jav
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:357)
at org.apache.tools.ant.Target.performTasks(Target.java:385)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
at org.romaframework.wizard.command.project.impl.ProjectAddModuleWizard.
at org.romaframework.wizard.command.project.impl.ProjectAddModuleWizard.
at org.romaframework.wizard.command.project.impl.ProjectCreateWizard.add
at org.romaframework.wizard.command.project.impl.ProjectCreateWizard.exe
at org.romaframework.wizard.MainWizard.main(Unknown Source)

Simplistic Texteditor for Your Next Ruby On Rails Webapplication

Introduction

Do you want to come to the metaparty? Okay it is not a party tool it is a political site in German where the party member itself create the party platform. The vision is: if you vote for metapartei you will get representative candidates which supports the oppinion of the nation – not of a specific lobby. As a member of Metapartei you can create concepts (ideas) and vote for them. At some day the set of all voted concepts will be our party platform.

Metapartei.de was written entirely with rails and with the help NetBeans as IDE (I could displace aptana ;-)). It is and it was really fun. Especially the database migrations in rails are fantastic for production! Okay sometimes ruby wasn’t that much fun. For example the following passes (very strange!):

assert_equal 2, "ÄÄa__".mb_chars.index("a", 4)

In the meanwhile we have to decide how the user can input some more than only text. If you would allow pure html then you would introduce a big security hole! For example someone could then insert any javascript function he likes with e.g. the <script> tag. So we need a rich text editor. But which one? There are a lot of editors out to allow the user to mark up the text. See the appendix for some we had evaluated. But we finally choose

Control.TextArea

from Ryan Johnson, because it is very small and highly customizable. See here for a life example. The small trade-off we had to pay was that we had to implement the conversation from wiki text to html. But this was relative easy. See The ruby code (under public domain) for the WikiText class, which implements the following behaviour:

  • ”bold” to bold
  • ”’italic”’ to italic
  • line breaks to <br />
  • and links like [http://www.metapartei.de Metapartei – a great idea] to Metapartei – a great idea

You can simply add other things (just let me know if you implement lists ;-)). But how you can embed the javascript with ruby? Here is the answer:

TextArea within Rails

Get the textarea.js from the TextArea bundle and put it under public/javascripts. Then create a file textarea_init.js from the code in the The javascript code section. Then insert

<%= javascript_include_tag 'textarea' %>

into app/views/layouts/application.html.erb (<head>HERE</head>). Then directly before the closing </body> tag write

<%= javascript_include_tag 'textarea_init' %>

Additionally you have to add a mark_down specific css file get it from the TextArea project too.

Now you can use it where you like. E.g. in the new template of the comments controller. Within new.html.erb add the following line as the very last:

<div id="markdown_formatted"></div>

But be sure that you specify at least one id for the text content (e.g. like we did: comment_content). See the javascript code section.

That’s it. Hope you enjoy it!

The ruby code

class WikiText
  def initialize(str)
    # process umlaute correctly
    @text = str.mb_chars
  end

  def to_html
    str, ii = process_sub_tag(nil, 0)
    str
  end  

  # returns the resulting string and the processed characters
  def process_sub_tag(until_tag_name, from_index)
    ii = from_index
    if(until_tag_name != nil)
      found_tag_index = @text.index(until_tag_name, from_index)
      if(found_tag_index != nil)
        until_index = found_tag_index + until_tag_name.length
      else
        return "", 0
      end
    end
    until_index = @text.length if until_index == nil

    result = ""
    while(ii < until_index)
      # F... ruby: '\n' != "\n"
      if (@text.at(ii) == "\n")
        result << "\n<br />"
        ii += 1

      elsif check_chars(ii, "'''")
        ii += 3
        if(until_tag_name == "'''")
          break
        end
        str, p_chars = process_sub_tag("'''", ii)
        result << "<b>" + str + "</b>"
        ii += p_chars

      elsif check_chars(ii, "''")
        ii += 2
        # closing tag
        if(until_tag_name == "''")
          break
        end
        last_index = @text.index("''", ii)
        if(last_index != nil)
          str, p_chars = process_sub_tag("''", ii)
          result << "<i>" + str + "</i>"
          ii += p_chars
        end

      elsif check_chars(ii, "]")
        ii += 1
        break;

      elsif check_chars(ii, "[")
        ii += 1
        last_index = @text.index("]", ii)
        if(last_index != nil)
          res = @text[ii, last_index-1].split(' ')
          if(res.length > 1 && !res[1].blank?)
            ii += res[0].length+1
            str, p_chars = process_sub_tag("]", ii)
            result << '<a target="_blank" href="'+ res[0]+'">'+str+"</a>"
            ii += p_chars
          end
        end
      else
        result << @text.at(ii)
        ii += 1
      end
    end
    return result, ii - from_index
  end

  # returns true if the specified chars match directly from the current position
  def check_chars(index, chars)
    len = chars.length
    #if (index > 0 && @text[index-1, 1] == chars.at(0) ||
    #      index + len < @text.length && @text[index+len, 1] == chars.at(0))
    #  return false
    #end
    @text[index, len] == chars
  end
end
# WARNING: with unicode it will not work 100%. See the strange assertion at the beginning of the blog post

The JavaScript code

/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/control/textarea
 * @require prototype.js, livepipe.js, textarea.js
 */

if(typeof(Control.TextArea) == "undefined")
    throw "Initialization requires Control.TextArea to be loaded.";

var idOfComponent = 'comment_content';
if($(idOfComponent) == null) {
    idOfComponent = 'concept_content';
}

if($(idOfComponent) != null) {
    var textarea = new Control.TextArea(idOfComponent);

    var toolbar = new Control.TextArea.ToolBar(textarea);

    //for css styles
    toolbar.container.id = 'markdown_toolbar';

    //buttons
    toolbar.addButton('Italics',function(){
        this.wrapSelection("''","''");
    },{
        id: 'markdown_italics_button'
    });

    toolbar.addButton('Bold',function(){
        this.wrapSelection("'''","'''");
    },{
        id: 'markdown_bold_button'
    });

    toolbar.addButton('Link',function(){
        var selection = this.getSelection();
        var response = prompt('Enter Link URL','');
        if(response == null)
            return;
        this.replaceSelection('[' + (response == '' ? 'http://link_url/' : response).
            replace(/^(?!(f|ht)tps?:\/\/)/,'http://') + ' ' + (selection == '' ? 'Link Text' : selection) + ']');
    },{
        id: 'markdown_link_button'
    });

    toolbar.addButton('Help',function(){
        window.open('/documents/wiki_text');
    },{
        id: 'markdown_help_button'
    });
}

Appendix

For more editors look here.

Very Small Hints for ActionMailer

Hi, I lost some hours to figure out, what the problems were to make sending via smtp working.

Here is a list you should check if something does not work:

  1. To enable raising exceptions during email sending make sure you add the following line into environment.rb:
    config.action_mailer.raise_delivery_errors = true
    Or put it into the test.rb or development.rb which will overwrite the settings specified in environment.rb
  2. Enable real email sending in test environment is possible in test.rb via
    config.action_mailer.delivery_method = :smtp
    instead of
    config.action_mailer.delivery_method = :test
    or directly use the following line in the test code
    ActionMailer::Base.delivery_method = :smtp
  3. if you get for your yahoo accout sth. like: EOFError: end of file reached.
    Or for your gmx account:
    Net::SMTPFatalError: 550 5.1.7 This server does not accept an empty envelope from ( http://portal.gmx.net/serverrules ) {mp038}
    You should check that the ‘from’ property is really only the email not anything else! (See the next point)
  4. If you use the restful_authentication plugin you can use the following code in user_mailer.rb:

    def setup_email(user,subj=nil)
    recipients  “#{user.email}”
    from        “#{FROM_EMAIL}”
    subject     “[#{SITE}] #{subj}”
    sent_on     Time.now
    body        :user => user
    end

    In environment.rb directly after the rails gem version constant add:

    SITE = ‘http://domain-you-like.de&#8217;
    FROM_EMAIL = ‘fromemail@gmx.de’

    And in the ‘Rails::Initializer.run do |config|’ block do:

    config.action_mailer.default_charset = “utf-8”
    config.action_mailer.delivery_method = :smtp
    config.action_mailer.smtp_settings = {
    :address => “mail.gmx.net” ,
    :port => 25,
    :domain => “localhost” ,
    :authentication => :login,
    :user_name => FROM_EMAIL ,
    :password => “donotshare”
    }

My stony way to find a ruby on the rails

Ruby is a great language. All can be expressed so short and readable. That’s one side.

The other side is: you have to learn a lot of exceptions to common stuff that you already learned in another languages (In my case Java).

So today I will explain things where it took me a lot of time to understand how to do this and what ruby (and rails) does. Let us start with the very basics: installation and then the pure ruby language.

Setup MySql

If you use debian as OS it is quite simple to install mysql:

sudo apt-get install mysql-server

Then create a database with the following lines

mysql -u root -p
type the following in the mysql shell:

CREATE DATABASE mydb;
GRANT ALL PRIVILEGES ON mydb.* TO 'admin'@'localhost' IDENTIFIED BY 'admin' WITH GRANT OPTION;
FLUSH PRIVILEGES;
quit;

Later on you can log into the mysql database via
mysql -u admin -p
[now type the password ‘admin’]

SHOW TABLES FROM mydb;

I suggest you to use http://www.squirrelsql.org/ to view and even manipulate the database. The nice thing about this java program is: you can simply install the jdbc drivers for your database (e.g sqlite or mysql) and after configuring them you can browse the databases in a nice way!

Install Ruby and Rails

To be independend from Java or if you don’t want to use JRuby you have to install ruby on your machine:

sudo apt-get install ruby libzlib-ruby rdoc irb

Now install gems …

sudo apt-get install rubygems
sudo gem install mysql

… and rails

sudo apt-get install rails

Create a Skeleton Application

Optionally install NetBeans 6.1 (and Java >1.5 before) to get some handy functionality.

Be sure that you choose a package with rails or install the rails plugins via: Tools->Plugins.

Now you should able to create a rails application: New Project->Ruby On Rails Application. Click Next and choose your ruby system. (Or do ‘rails testapp’ on the command line).

You will get a list of created files. To quickly navigate to a file in NetBeans press ALT+SHIFT+O (Oh not zero) and type in the name. Now I will go through some of the generated files:

app/controllers/application.rb

This is the base class for all of our controllers. To study the Model-View-Controller pattern visit wikipedia. In our controllers we put in all of our application logic. For example the password encryption when one of our user logs in.

app/helpers/application_helper.rb

In this helper modul we define some convinient methods for our view

test/test_helper.rb

With this class it is easy to test the implemented (helper) methods. Read “Agile Web Development with Rails” to be surprised that unit and even integration tests are very easy (and fast) to write.
config/database.yml
The generated content looks like:
development:
# your database server:
adapter: mysql
encoding: utf8
database: mydb
username: admin
password: admin
timeout: 5000
# necessary if you are on debian:
socket: /var/run/mysqld/mysqld.sock

config/routes.rb
Here you will define later more fine grained navigation rules for the pages of your web application.

In NetBeans (with rails of course) database-migrating is very easy: right click the project->Migrate Database->To [misc] Version or Clear…

Start the web server with F6 in NetBeans or type

ruby script\server

Then go to http://localhost:3000/ with your browser and you should see ruby’s welcome page.

Now we want to replace the index.html with an erb (like jsp) file. To do this we will remove the public/index.html file and do

script/generate controller home index

add the following to the routes.rb

map.home '', :controller => 'home', :action => 'index'

To add some more functionality to our rails application there are a lot of plugins available. One of them is the restful_authentication, where a tutorial plugin (or here) exists which itself references to a bunch of other useful plugins. Check them out!.

Now some comments on setting up the restful_authentication plugin: Add the following resource to your repositories if you need this plugin (and others from the author):

script/plugin source http://svn.techno-weenie.net/projects/plugins/script/plugin install restful_authentication

or simply do

script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/

On my machine it took a lot of time and finished with an timeout error so I did:

sudo apt-get install git-corecd vendor/plugin && git clone git://github.com/activefx/restful_authentication.gitmv restful-authentication/ restful_authentication/ && cd ../..

Now generate the necessary classes:

script/generate authenticated user sessions --include-activation --stateful

My (unsorted) Comments

Try getting started with rails and come back here to read the following comments (or post your own!) if you figured out sth. worth enough to be said for beginners.

  1. For restful_authentication:
    Be sure that you ignore the config/initializers/site_keys.rb in your subversion!! But save it, because you will need it for your application!
  2. If need a login snippet like the one from the authentication tutorial:
    app/views/users/_user_bar.html.erb in your start up weü page app/views/home/index.html.erb
    Use the following line:
    <%= render(:partial => “users/user_bar”) %>
  3. If you need ssh2 try:
    # require ‘digest/sha1’
    require ‘digest/sha2’
    def User.mydigest(str)
    Digest::SHA256.digest(str)
    #Digest::SHA1.hexdigest(str)
    end
  4. What the hell is this string with a colon? I mean the ‘:password’ here:
    update_attributes :password => ‘secure’
    It is called symbol and is the name of a variable e.g. of a class. Where ‘secure’ is the value of the variable password. So with this method call e.g. within the User class you do password = ‘secure’.
    Example:
    var = { ‘a’ => ‘b’, 1 => ‘c’}
    assert_equals(‘b’, var[‘a’])
  5. And what is the :password => ‘secure’ statement?
    This is a key => value expression without the {} braces of the hash (Map in Java) , which are optional if the hash is the last parameter. This is very handy if you have several properties to set.
  6. What is ‘self’? It depends! Read more about self here!
    • global variables begins with @@
    • object variables begins with an @ (All the instance methods of a class can access this variable. So every object has its own set of object variables.)
    • local variable begins with a lower case character (except ‘self’)
    • constant variables begins with an upper case character (except ‘:symbol’)

    Warning: if you don’t add self in front of you object variables, ruby assumes that they are local!?

  7. What is attr_accessor :name? This will create a getter and a setter for the variable ‘name’.
    Or define a setter manually (via operator overloading)
    def volume=(vol)
    leftChannel = self.rightChannel = vol
    end
  8. Where is the constructor of User? Do
    user = User.new
  9. escape html in the view via h(user_input).
    For more security related stuff look here, here and here.
  10. The following line is not always secure (‘mass assignment’)
    User.new(params[:user])
    To make it secure do:
    attr_accessible :name
    Now only the variable name can be change via url parameters.
  11. The following statement is unsecure
    User.find(:all, :conditions => [“name like ‘%#{params[:query]}%'”])
    Use
    :conditions => “name like ?”, ‘%’ + params[:query] + ‘%’
  12. add filter_parameter_logging :password to application.rb
    => all fields with names like “password” will get [FILTERED] in the logs
  13. Rails add a very handy method to objects:
    o.blank?
    An object is blank if it‘s false, empty, or a whitespace string. For example, “”, ” “, nil, [], and {} are blank. Taken from here.
  14. There is no counter++
    Use counter += 1
  15. Swapping variables:
    a, b = b, a
    This work in methods too! E.g. return a pair of variables via
    def meth
    return a, b
    end
    Now call the method
    b, a = meth
  16. if sugar – ‘the other wayround’
    puts ‘hello world’ if str == ‘name’
  17. defined? var
    will return true if there is a field named var
  18. You can use ‘hello’ or “hello”
    The only difference for those strings is the expression evaluation like “#{var}”
    This will work only in “”
  19. comments are like in bash: #
    Or use this to comment several lines:
    =begin
    here is comment
    here too. WARING: =begin and =end has to be the first characters on the lines!
    =end
  20. Default values for method parameters via
    def meth(param=’test’)
    end
  21. def see_how_to_throw
    begin
    # Do something nifty
    raise SomeError, “This is the error message!”
    rescue SomeError
    # This is executed when a SomeError exception is raised
    # to rethrow do
    # raise $!
    rescue AnotherError => error
    # Here, the exception object is referenced from the
    # `error’ variable
    else
    # This is executed only if no exceptions were raised
    ensure
    # This is always executed, exception or not
    end
    end
  22. A very useful tool for testing is autotest:
    gem install ZenTest
  23. It is eays to test with rails! Very easy to write unit and functional testing of your controllers and the pages.
    In NetBeans press ALT+F6 to start them.
  24. use %{ } for xml strings directly unescaped in the code! Very handy.
  25. Time sugar:
    3.minutes + 3.hours
    returns the result in seconds! Much more …
  26. counter ||= 0
    This statement will only be executed if counter is nil. Useful for singletons you think? Use self for this!
  27. Unicode support is not that good. Use Chars instead of the built in String class. Or convert to Chars before working with strings.
  28. Why are there named routes in routes.rb?
    These routes are accessible from the view. E.g. the following line is a named route (map.hello instead of map.resource)
    map.hello ‘/fhello’, :controller => ‘users’, :action => ‘hello’
    So the method hello will be invoke if the user click the link in the view which is generated via <%=hello_url%>
    One special name ‘map.resources’ indicates that rails should create 7 standard routes (4 of them are the CRUD methods). For example map.resources :articles will create the following routes:
    /articles (GET=>shows all, POST=>create a new)
    /articles/new (shows html for new article)
    /articles/1 (GET=>shows the first article, PUT=>update, DELETE=>deletes the article)
    /articles/1;edit
  29. parsing invalid xml with require ‘rubygems’ and require ‘rubyful_soup’. Then do:
    xml_data = Net::HTTP.get_response(URI.parse(url)).body
    doc = BeautifulSoup.new(xml_data)